Skip to main content

compio_driver\sys\op\fs/
mod.rs

1cfg_select! {
2    windows => {
3        mod iocp;
4    }
5    fusion => {
6        mod iour;
7        mod poll;
8        mod_use![fusion];
9    }
10    io_uring => {
11        mod_use![iour];
12    }
13    polling => {
14        mod_use![poll];
15    }
16    stub => {
17        mod_use![stub];
18    }
19    _ => {}
20}
21
22use crate::sys::prelude::*;
23
24/// Close the file fd.
25pub struct CloseFile {
26    pub(crate) fd: ManuallyDrop<OwnedFd>,
27}
28
29impl CloseFile {
30    /// Create [`CloseFile`].
31    pub fn new(fd: OwnedFd) -> Self {
32        Self {
33            fd: ManuallyDrop::new(fd),
34        }
35    }
36}
37
38/// Read an extended attribute from a path, following the final symbolic link.
39///
40/// The result is the number of bytes written, or the required size when the
41/// buffer has zero capacity. This operation does not update the buffer's
42/// initialized length.
43///
44/// Uses native io-uring when supported; otherwise the syscall runs on the
45/// driver's blocking pool.
46#[cfg(linux_all)]
47pub struct GetXattr<T: IoBufMut> {
48    pub(crate) path: CString,
49    pub(crate) name: CString,
50    pub(crate) buffer: T,
51}
52
53#[cfg(linux_all)]
54impl<T: IoBufMut> GetXattr<T> {
55    /// Create [`GetXattr`], retaining the path, name, and buffer until completion.
56    pub fn new(path: CString, name: CString, buffer: T) -> Self {
57        Self { path, name, buffer }
58    }
59
60    pub(crate) fn call(&mut self, _: &mut ()) -> io::Result<usize> {
61        let slice = self.buffer.sys_slice_mut();
62        // SAFETY: both C strings are owned by this operation and remain valid.
63        // The exclusively borrowed buffer exposes its entire writable capacity,
64        // including uninitialized bytes. A size query writes no bytes.
65        syscall!(libc::getxattr(
66            self.path.as_ptr(),
67            self.name.as_ptr(),
68            slice.ptr().cast(),
69            slice.len(),
70        ))
71    }
72}
73
74#[cfg(linux_all)]
75impl<T: IoBufMut> IntoInner for GetXattr<T> {
76    type Inner = T;
77
78    fn into_inner(self) -> Self::Inner {
79        self.buffer
80    }
81}
82
83/// Read an extended attribute from an open file using `fgetxattr` semantics.
84///
85/// The result is the number of bytes written, or the required size when the
86/// buffer has zero capacity. This operation does not update the buffer's
87/// initialized length.
88///
89/// Uses native io-uring when supported; otherwise the syscall runs on the
90/// driver's blocking pool.
91#[cfg(linux_all)]
92pub struct FGetXattr<S: AsFd, T: IoBufMut> {
93    pub(crate) fd: S,
94    pub(crate) name: CString,
95    pub(crate) buffer: T,
96}
97
98#[cfg(linux_all)]
99impl<S: AsFd, T: IoBufMut> FGetXattr<S, T> {
100    /// Create [`FGetXattr`], retaining the fd, name, and buffer until completion.
101    pub fn new(fd: S, name: CString, buffer: T) -> Self {
102        Self { fd, name, buffer }
103    }
104
105    pub(crate) fn call(&mut self, _: &mut ()) -> io::Result<usize> {
106        let slice = self.buffer.sys_slice_mut();
107        // SAFETY: the fd and C string are retained by this operation. The
108        // exclusively borrowed buffer exposes its entire writable capacity,
109        // including uninitialized bytes. A size query writes no bytes.
110        syscall!(libc::fgetxattr(
111            self.fd.as_fd().as_raw_fd(),
112            self.name.as_ptr(),
113            slice.ptr().cast(),
114            slice.len(),
115        ))
116    }
117}
118
119#[cfg(linux_all)]
120impl<S: AsFd, T: IoBufMut> IntoInner for FGetXattr<S, T> {
121    type Inner = T;
122
123    fn into_inner(self) -> Self::Inner {
124        self.buffer
125    }
126}
127
128/// Sync data to the disk.
129pub struct Sync<S> {
130    pub(crate) fd: S,
131    #[allow(dead_code)]
132    pub(crate) datasync: bool,
133}
134
135impl<S> Sync<S> {
136    /// Create [`Sync`].
137    ///
138    /// If `datasync` is `true`, the file metadata may not be synchronized.
139    pub fn new(fd: S, datasync: bool) -> Self {
140        Self { fd, datasync }
141    }
142}
143
144/// Splice data between two file descriptors.
145#[cfg(linux_all)]
146pub struct Splice<S1, S2> {
147    pub(crate) fd_in: S1,
148    pub(crate) offset_in: i64,
149    pub(crate) fd_out: S2,
150    pub(crate) offset_out: i64,
151    pub(crate) len: usize,
152    pub(crate) flags: rustix::pipe::SpliceFlags,
153}
154
155#[cfg(linux_all)]
156impl<S1, S2> Splice<S1, S2> {
157    /// Create [`Splice`].
158    ///
159    /// `offset_in` and `offset_out` specify the offset to read from and write
160    /// to. Use `-1` for pipe ends or to use/update the current file
161    /// position.
162    pub fn new(
163        fd_in: S1,
164        offset_in: i64,
165        fd_out: S2,
166        offset_out: i64,
167        len: usize,
168        flags: rustix::pipe::SpliceFlags,
169    ) -> Self {
170        Self {
171            fd_in,
172            offset_in,
173            fd_out,
174            offset_out,
175            len,
176            flags,
177        }
178    }
179
180    pub(crate) fn call(&self, _: &mut ()) -> io::Result<usize>
181    where
182        S1: AsFd,
183        S2: AsFd,
184    {
185        let off_in = self.offset_in;
186        let off_out = self.offset_out;
187
188        rustix::pipe::splice(
189            &self.fd_in,
190            (off_in >= 0).then_some(&mut (off_in as u64)),
191            &self.fd_out,
192            (off_out >= 0).then_some(&mut (off_out as u64)),
193            self.len,
194            self.flags,
195        )
196        .map_err(Into::into)
197    }
198}
199
200#[cfg(linux_all)]
201impl<S1, S2> IntoInner for Splice<S1, S2> {
202    type Inner = (S1, S2);
203
204    fn into_inner(self) -> Self::Inner {
205        (self.fd_in, self.fd_out)
206    }
207}